<template>
	<view class="wrapper" :style="'font-size: '+fontSize+'rpx;'" v-if="text">
		<!-- 隐藏的画布，用于测量 -->
		<canvas canvas-id="helper" style="position: fixed; left: -9999px; top: -9999px;"></canvas>
		<!-- 展开状态：直接全文 -->
		<text v-if="isExpand" class="full-text">{{ text }} <text class="btn" v-if="isExceeds"
				@tap.stop="isExpand = false">收起</text></text>

		<!-- 折叠状态：截取到第 4 行末尾 + 内联按钮 -->
		<view v-else>
			<text>{{ clampText }}</text>
			<text class="clamp-text">...<text class="btn1" @tap.stop="isExpand = true">展开</text></text>

		</view>
	</view>
</template>

<script>
	export default {
		props: {
			text: {
				type: String,
				default: ''
			},
			lineCount: {
				type: Number,
				default: 4
			}, // 需要截断的行数
			fontSize: {
				type: Number,
				default: 28
			}, // 字体大小rpx
		},
		data() {
			return {
				isExpand: false, //展开全部
				isExceeds: false, //是否超出截断的行数
				clampText: '', // 手动截断后的文本
			};
		},
		mounted() {
			this.$nextTick(() => {
				this.calcClamp();
			})

		},
		methods: {
			/* 计算一行能放多少汉字，然后截断 */
			async calcClamp() {
				let rect = await this.getRect('.wrapper')

				if (!rect) return;

				const ratio = uni.upx2px(this.fontSize); // 1rpx -> px

				const ctx = uni.createCanvasContext('helper');
				ctx.setFontSize(ratio);
				let numStr = 0 //字符串的宽度总数
				let line = 1 //当前所在行数
				let nowIndex = 0 //当前数字所在索引

				let lookText = await this.getRect('.clamp-text') //更多按钮
				for (let i = 0; i < this.text.length; i++) {
					let w = ctx.measureText(this.text[i]).width; // 获取文字的宽度，返回 rpx
					numStr += w
					if (line >= this.lineCount) {
						//判断是否是最后一行,最后一行需要减去更多按钮的宽度
						if (numStr >= rect.width - lookText.width - 10) {
							nowIndex = i
							break;
						} else {
							nowIndex = i
						}
					} else {
						// 判断是否超出屏幕宽度，超出则换一行重新记录，没有就累加宽度
						if (this.text[i] === '\n' || this.text[i] === '\r') {
							line++
							numStr = w
							nowIndex = i
						} else {
							if (numStr >= rect.width) {
								numStr = w
								line++
								nowIndex = i
							} else {
								nowIndex = i
							}
						}

					}
				}
				if (line < this.lineCount - 1) {
					this.isExceeds = false
					this.isExpand = true // 不足 4 行
				} else {
					if (this.text.length > nowIndex + 1) {
						this.isExceeds = true
						this.clampText = this.text.slice(0, nowIndex); //截断的字符长度
					} else {
						this.isExceeds = false
						this.isExpand = true // 不足 4 行
					}
				}

			},
			getRect(selector) {
				return new Promise(resolve => {
					uni.createSelectorQuery()
						.in(this)
						.select(selector)
						.boundingClientRect(rect => resolve(rect))
						.exec();
				});
			},

		},
	};
</script>

<style scoped>
	.wrapper {
		line-height: 1.6;
		word-break: break-all;
		color: #333;
		position: relative;
		text-align: justify;
	}

	.btn {
		color: #4078E5;
	}

	.clamp-text {
		width: 84rpx;
		display: inline-block;
	}

	.btn1 {
		color: #4078E5;
		position: absolute;
		right: 0;
	}
</style>